/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package net.octopeer.message;

import java.io.File;
import java.io.StringReader;

import java.util.ArrayList;

import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;

import org.xml.sax.InputSource;

import net.octopeer.core.PeerNode;
import net.octopeer.core.Resource;
import net.octopeer.utilities.XMLTools;
import net.octopeer.utilities.SimpleSHA1;

/**
 *
 * @author andria
 */
public class Respond {
    private String resID;
    private String reqID;
    private Resource resDetail;
    private PeerNode resNode;
    private ArrayList<PeerNode> pathPeers;
    
    public Respond() {
        this.pathPeers = new ArrayList<PeerNode>();
    }
    
    public Respond(String reqID, Resource resDetail, PeerNode resNode, ArrayList<PeerNode> pathPeers) throws Exception {
        this.reqID = reqID;
        this.resDetail = resDetail;
        this.resNode = resNode;
        this.pathPeers = pathPeers;
        this.resID = SimpleSHA1.SHA1(reqID + resDetail.getResourceID());
    }
    
    public Respond(String reqID, Resource resDetail, PeerNode resNode, PeerNode pathPeer) throws Exception {
        this.reqID = reqID;
        this.resDetail = resDetail;
        this.resNode = resNode;
        this.pathPeers = new ArrayList<PeerNode>();
        this.pathPeers.add(pathPeer);
        this.resID = SimpleSHA1.SHA1(reqID + resDetail.getResourceID());
    }
    
    public Respond(Respond oldRep) {
        this.resID = oldRep.getResID();
        this.reqID = oldRep.getReqID();
        this.resDetail = oldRep.getResDetail();
        this.resNode = oldRep.getResNode();
        this.pathPeers = oldRep.getPathPeers();
    }
    
    public void setResID(String resID) {
        this.resID = resID;
    }
    
    public void setReqID(String reqID) {
        this.reqID = reqID;
    }
    
    public void setResDetail(Resource resDetail) {
        this.resDetail = resDetail;
    }
    
    public void setResNode(PeerNode resNode) {
        this.resNode = resNode;
    }
    
    public void setPathPeers(ArrayList<PeerNode> pathPeers) {
        this.pathPeers = pathPeers;
    }
    
    public void addPathPeer(PeerNode peer) {
        this.pathPeers.add(peer);
    }
    
    public PeerNode remPathPeer() {
        return this.pathPeers.remove(this.pathPeers.size() -1);
    }
    
    public String getResID() {
        return this.resID;
    }
    
    public String getReqID() {
        return this.reqID;
    }
    
    public Resource getResDetail() {
        return this.resDetail;
    }
    
    public PeerNode getResNode() {
        return this.resNode;
    }
    
    public ArrayList<PeerNode> getPathPeers() {
        return this.pathPeers;
    }
    
    public Document toXMLDoc() throws Exception {
        Document doc;
        XMLTools xt = new XMLTools();        
        doc = xt.db.newDocument();
        
        Element rootEle = doc.createElement("Respond");

        // ResID
        Element resIDEle = doc.createElement("Respond:ID");
        Text resIDText = doc.createTextNode(this.resID);
        resIDEle.appendChild(resIDText);
        rootEle.appendChild(resIDEle);  
        
        // ReqID
        Element reqIDEle = doc.createElement("Respond:RequestID");
        Text reqIDText = doc.createTextNode(this.reqID);
        reqIDEle.appendChild(reqIDText);
        rootEle.appendChild(reqIDEle);  
                
        // ResDetail
        Element resDetailEle = doc.createElement("Respond:Detail");
            // ID
            Element resDetailIDEle = doc.createElement("Respond:Detail:ID");
            Text resDetailIDText = doc.createTextNode(this.resDetail.getResourceID());
            resDetailIDEle.appendChild(resDetailIDText);
            resDetailEle.appendChild(resDetailIDEle);        

            // Type
            Element resDetailTypeEle = doc.createElement("Respond:Detail:Type");
            Text resDetailTypeText = doc.createTextNode(this.resDetail.getResourceType());
            resDetailTypeEle.appendChild(resDetailTypeText);
            resDetailEle.appendChild(resDetailTypeEle);        

            // Detail
            Element resDetailDetailEle = doc.createElement("Respond:Detail:Detail");
            Text resDetailDetailText = doc.createTextNode(this.resDetail.getResourceDetail());
            resDetailDetailEle.appendChild(resDetailDetailText);
            resDetailEle.appendChild(resDetailDetailEle);        
        rootEle.appendChild(resDetailEle); 
        
        // ResNode
        Element resNodeEle = doc.createElement("Respond:Node");
        
        // ID
        Element resNodeIDEle = doc.createElement("Respond:Node:ID");
        Text resNodeIDText = doc.createTextNode(resNode.getNodeID());
        resNodeIDEle.appendChild(resNodeIDText);
        resNodeEle.appendChild(resNodeIDEle);        

        // IPaddress
        Element resNodeIPaddressEle = doc.createElement("Respond:Node:IPaddress");
        Text resNodeIPaddressText = doc.createTextNode(resNode.getNodeIPaddress());
        resNodeIPaddressEle.appendChild(resNodeIPaddressText);
        resNodeEle.appendChild(resNodeIPaddressEle);        

        // Port
        Element resNodePortEle = doc.createElement("Respond:Node:Port");
        Text resNodePortText = doc.createTextNode(Integer.toString(resNode.getNodePort()));
        resNodePortEle.appendChild(resNodePortText);
        resNodeEle.appendChild(resNodePortEle);  
        
        rootEle.appendChild(resNodeEle);
        
        // PathPeers
        Element pathPeersEle = doc.createElement("Respond:Path");
        
            int pathPeersLoop = 0;
            PeerNode pathPeerNode = null;

            while (pathPeersLoop < this.pathPeers.size()) {
                Element pathPeerNodeEle = doc.createElement("Respond:Path:Node");
                pathPeerNode = (PeerNode) this.pathPeers.get(pathPeersLoop);

                // ID
                Element pathPeerNodeIDEle = doc.createElement("Respond:Path:Node:ID");
                Text pathPeerNodeIDText = doc.createTextNode(pathPeerNode.getNodeID());
                pathPeerNodeIDEle.appendChild(pathPeerNodeIDText);
                pathPeerNodeEle.appendChild(pathPeerNodeIDEle);        

                // IPaddress
                Element pathPeerNodeIPaddressEle = doc.createElement("Respond:Path:Node:IPaddress");
                Text pathPeerNodeIPaddressText = doc.createTextNode(pathPeerNode.getNodeIPaddress());
                pathPeerNodeIPaddressEle.appendChild(pathPeerNodeIPaddressText);
                pathPeerNodeEle.appendChild(pathPeerNodeIPaddressEle);        

                // Port
                Element pathPeerNodePortEle = doc.createElement("Respond:Path:Node:Port");
                Text pathPeerNodePortText = doc.createTextNode(Integer.toString(pathPeerNode.getNodePort()));
                pathPeerNodePortEle.appendChild(pathPeerNodePortText);
                pathPeerNodeEle.appendChild(pathPeerNodePortEle);        

                pathPeersEle.appendChild(pathPeerNodeEle);
                pathPeersLoop++;
            }
                
        rootEle.appendChild(pathPeersEle); 
        
        doc.appendChild(rootEle);                
        
        return doc;
    }
    
    public String toXMLString() throws Exception {
        String result = null;
        
        XMLTools xt = new XMLTools();                
        result = xt.writeXMLString(this.toXMLDoc());
        
        return result;
    }
    
    public void toXMLFile(String fileName) throws Exception {
        // Prepare the DOM document for writing
        Source source = new DOMSource(this.toXMLDoc());

        // Prepare the output file
        File file = new File(fileName);
        Result result = new StreamResult(file);

        // Write the DOM document to the file
        Transformer xformer = TransformerFactory.newInstance().newTransformer();
        xformer.transform(source, result);
    }
    
    public Respond fromXMLDoc(Document dom) {
        Respond result = new Respond();
        
        Element rootEle = dom.getDocumentElement();
        
        if (rootEle.getTagName().equals("Respond")) {
            // ResID
            NodeList resIDList = rootEle.getElementsByTagName("Respond:ID");
            String resIDText = resIDList.item(0).getFirstChild().getNodeValue();
            result.setResID(resIDText);
            
            // ReqID
            NodeList reqIDList = rootEle.getElementsByTagName("Respond:RequestID");
            String reqIDText = reqIDList.item(0).getFirstChild().getNodeValue();
            result.setReqID(reqIDText);
            
            // ResDetail
            Resource resourceDetail = new Resource();
            
            NodeList resourceIDList = rootEle.getElementsByTagName("Respond:Detail:ID");
            String resourceIDText = resourceIDList.item(0).getFirstChild().getNodeValue();
            NodeList resourceTypeList = rootEle.getElementsByTagName("Respond:Detail:Type");
            String resourceTypeText = resourceTypeList.item(0).getFirstChild().getNodeValue();
            NodeList resourceDetailList = rootEle.getElementsByTagName("Respond:Detail:Detail");
            String resourceDetailText = resourceDetailList.item(0).getFirstChild().getNodeValue();
            resourceDetail.setResourceID(resourceIDText);
            resourceDetail.setResourceType(resourceTypeText);
            resourceDetail.setResourceDetail(resourceDetailText);
            
            result.setResDetail(resourceDetail);
            
            // ResNode
            PeerNode resNode = new PeerNode();
            
            NodeList resNodeIDList = rootEle.getElementsByTagName("Respond:Node:ID");
            String resNodeIDText = resNodeIDList.item(0).getFirstChild().getNodeValue();
            NodeList resNodeIPadressList = rootEle.getElementsByTagName("Respond:Node:IPaddress");
            String resNodeIPaddressText = resNodeIPadressList.item(0).getFirstChild().getNodeValue();
            NodeList resNodePortList = rootEle.getElementsByTagName("Respond:Node:Port");
            String resNodePortText = resNodePortList.item(0).getFirstChild().getNodeValue();
             
            resNode.setNodeID(resNodeIDText);
            resNode.setNodeIPaddress(resNodeIPaddressText);
            resNode.setNodePort(Integer.valueOf(resNodePortText));
            
            result.setResNode(resNode);

            // PathPeers
            NodeList pathPeersList = rootEle.getElementsByTagName("Respond:Path");
            NodeList pathPeersNodeList = rootEle.getElementsByTagName("Respond:Path:Node");

            int pathPeersLoop = 0;
            
            while (pathPeersLoop < pathPeersNodeList.getLength()) {
                NodeList pathPeersNodeListEle = pathPeersNodeList.item(pathPeersLoop).getChildNodes();
                
                PeerNode pathPeerNode = new PeerNode();
                
                String pathPeerNodeIDText = pathPeersNodeListEle.item(0).getFirstChild().getNodeValue();
                String pathPeerNodeIPaddressText = pathPeersNodeListEle.item(1).getFirstChild().getNodeValue();
                String pathPeerNodePortText = pathPeersNodeListEle.item(2).getFirstChild().getNodeValue();

                pathPeerNode.setNodeID(pathPeerNodeIDText);
                pathPeerNode.setNodeIPaddress(pathPeerNodeIPaddressText);
                pathPeerNode.setNodePort(Integer.valueOf(pathPeerNodePortText));

                result.pathPeers.add(pathPeerNode);
                
                pathPeersLoop++;
            }
        }
                
        return result;
    }
    
    public Respond fromXMLString(String data) throws Exception {
        Document dom = null;
        XMLTools xt = new XMLTools();
        Respond result = null;
        
        // Parse the XML stream input to Document type
        dom = xt.db.parse(new InputSource(new StringReader(data)));
        
        result = fromXMLDoc(dom);
        
        return result;
    }
    
    public Respond fromXMLFile(String fileName) throws Exception {
        Document dom = null;
        File file = null;
        Respond result = null;
        XMLTools xt = new XMLTools();
        
        // Parse the XML stream input to Document type
        file = new File(fileName);
        dom = xt.db.parse(file);
        
        result = fromXMLDoc(dom);
        
        return result;
    }   
    
//    public static void main(String[] args) throws Exception {
//        Resource res1 = new Resource("file", "./share/1.res");
//        Request req1 = new Request();
//        req1 = req1.fromXMLFile("./conf/req1.xml");
//        PeerNode p1 = new PeerNode("192.168.0.1", 9090);
//        PeerNode p2 = new PeerNode("192.168.0.2", 9090);
//        PeerNode p3 = new PeerNode("192.168.0.3", 9090);
//        PeerNode p4 = new PeerNode("192.168.0.4", 9090);
//        Respond rep1 = new Respond(req1.getReqID(), res1, p4, p1);
//        rep1.addPathPeer(p2);
//        rep1.addPathPeer(p3);
//        rep1.addPathPeer(p4);
//        
//        rep1.toXMLFile("./conf/rep1.xml");
//        Respond rep1 = new Respond();
//        rep1 = rep1.fromXMLFile("./conf/rep1.xml");
//        rep1.toXMLFile("./conf/rep2.xml");
//    }
}
